package com.filldream.fastboot.common.util;

import java.lang.reflect.Field;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 树形工具类
 *
 * @author RickSun
 * @data 2024-01-16
 */
public class TreeUtil {

    /**
     * 将List转换成Tree
     *
     * @param list               包含子集字段的原始List
     * @param parentKeyExtractor 父级ID字段
     * @param superParentId      顶级父级ID
     * @param idKeyExtractor     主键字段
     * @param sortKeyExtractor   排序字段
     * @param <T>
     * @param <P>
     * @param <I>
     * @return
     */
    public static <T, P, I> List<T> getTree(List<T> list,
                                            Function<T, P> parentKeyExtractor,
                                            P superParentId,
                                            Function<T, I> idKeyExtractor,
                                            Function<T, Integer> sortKeyExtractor) {
        String childKey = "dataList";
        return list.stream()
                .filter(type -> parentKeyExtractor.apply(type).equals(superParentId))
                .peek(item -> {
                    setPropertyValue(item, childKey, getChildren(item, list, parentKeyExtractor, idKeyExtractor, sortKeyExtractor));
                })
                .collect(Collectors.toList());
    }

    /**
     * 递归子集
     *
     * @param root
     * @param list
     * @param parentKeyExtractor
     * @param idKeyExtractor
     * @param sortKeyExtractor
     * @param <T>
     * @param <P>
     * @param <I>
     * @return
     */
    private static <T, P, I> Object getChildren(T root,
                                                List<T> list,
                                                Function<T, P> parentKeyExtractor,
                                                Function<T, I> idKeyExtractor,
                                                Function<T, Integer> sortKeyExtractor) {
        return list.stream()
                .filter(item -> parentKeyExtractor.apply(item).equals(idKeyExtractor.apply(root)))
                .peek(item ->
                        setPropertyValue(item, "dataList", getChildren(item, list, parentKeyExtractor, idKeyExtractor, sortKeyExtractor))
                )
                .sorted((t2, t1) -> Integer.compare(sortKeyExtractor.apply(t1), sortKeyExtractor.apply(t2)))
                .collect(Collectors.toList());
    }

    /**
     * 获取属性值
     *
     * @param object
     * @param propertyName
     * @param <T>
     * @param <R>
     * @return
     */
    private static <T, R> R getPropertyValue(T object, String propertyName) {
        try {
            Class<?> clazz = object.getClass();
            Field field = clazz.getDeclaredField(propertyName);
            field.setAccessible(true);
            @SuppressWarnings("unchecked")
            R value = (R) field.get(object);
            return value;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 设置属性值
     *
     * @param object
     * @param propertyName
     * @param propertyValue
     * @param <T>
     * @param <R>
     */
    private static <T, R> void setPropertyValue(T object, String propertyName, R propertyValue) {
        try {
            Class<?> clazz = object.getClass();
            Field field = clazz.getDeclaredField(propertyName);
            field.setAccessible(true);
            field.set(object, propertyValue);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
